This is a thin subsystem, where components can send their audit messages.
The subsystem will then forward those to one of
Server subsystem implementation
The receiver must be asynchronous, so that a subsystem that is sending audit logs is not blocked by waiting for the record to be written.
There would probably be a manager like this, which runs as a local (interfaceless) EJB, which offers a method addRecord :
package org.rhq.enterprise.server.audit;
import java.util.concurrent.Future;
import javax.ejb.AsyncResult;
import javax.ejb.Asynchronous;
import javax.ejb.Stateless;
@Stateless
public class AuditManagerBean {
@Asynchronous
public Future<CID> addRecord(AuditRecord record) {
addRecord() gets an audit record passed (see below) and returns a Future. The Future returns a correlation id, so that it is possible to log further info with this id as e.g. when
-
an operation is started, the above is called and the correlation id is returned.
-
after the operation has finished, the outcome is logged along with the correlation id, so that the start and end events can be correlated together to form one "big event".
The exact format of CID needs to be determined, it may probably be a tiny object that consists of current time (long) + thread id (int) to make it unique when two subsystems want to log at the very same point in time (some systems, especially Windows have/had timers where current time ms was advanced in 10ms steps only, so that this is not unique enough).
If no correlation is needed, then the returned Future can just be ignored.
We may also offer a method signature, where the individual parts of the AuditRecord are just passed as individual fields.
It is important that the addRecord() method runs decoupled from the transaction it may be called from to prevent the message from being lost when the calling transaction rolls back. This may already be given by marking the method with @Asynchronous, but we need to check that.
Audit record
An AuditRecord may look like this.
public class AuditRecord {
private Subsystem subsystem; // Subsystem that is audited
private long correlationId;
private Subject user; // User that generated this audit event; will internally used as user.userName
private String message; // Message to log
We may consider also adding a field for a unique identifier RHQxxxxx to each audit event, that can be further explained in the documentation.
The Subject user will internally in the AuditManagerBean be turned into a string that has the name of the Subject
Subsystem could look like this (needs extension and rewording for sure):
public enum Subsystem {
ADMINISTRATION,
AUDIT,
BUNDLE,
CONFIGURATION,
CONTENT,
DRIFT,
EVENT,
INVENTORY,
MEASUREMENT,
OPERATIONS,
REST
;
}